#include "common/pch.h"
#include "world/world.h"

#include <cmath>
#include <format>

#include <cftc/timemeter/interval.h>
#include <cftf/loger/syslog.h>

#include "metadata/metamgr.h"
#include "object/object.h"
#include "object/player.h"
#include "object/objectmgr.h"
#include "map/griddefines.h"
#include "map/mapmgr.h"
#include "map/map_persistent_state_mgr.h"
#include "map/poolmgr.h"

#ifndef MANGOSD_CONFIG_VERSION
# define MANGOSD_CONFIG_VERSION 2023053000
#endif

#define DEFAULT_PLAYER_LIMIT 100
#define DEFAULT_WORLDSERVER_PORT 8085                       //8129
#define DEFAULT_REALMSERVER_PORT 3724

float World::m_MaxVisibleDistanceOnContinents = DEFAULT_VISIBILITY_DISTANCE;
float World::m_MaxVisibleDistanceInInstances = DEFAULT_VISIBILITY_INSTANCE;
float World::m_MaxVisibleDistanceInBGArenas = DEFAULT_VISIBILITY_BGARENAS;

float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE;
float World::m_VisibleUnitGreyDistance = 0;
float World::m_VisibleObjectGreyDistance = 0;

float  World::m_relocation_lower_limit_sq = 10.f * 10.f;
unsigned World::m_relocation_ai_notify_delay = 1000u;

enum AccountTypes
{
    SEC_PLAYER = 0,
    SEC_MODERATOR = 1,
    SEC_GAMEMASTER = 2,
    SEC_ADMINISTRATOR = 3,
    SEC_CONSOLE = 4                                  // must be always last in list, accounts must have less security level always also
};


World::World()
{
    m_broadcastTimer = std::make_shared<cftc::timemeter::Interval>();
    m_gameTime = time(NULL);
}

void World::Init()
{
	LoadConfigSettings(false);

    cftf::loger::SysLog::Instance().Info("Starting Map System");
    MapMgr::Instance().Init();

    cftf::loger::SysLog::Instance().Info("Loading Objects Pooling Data...");
    PoolManager::Instance().LoadFromDB();

    cftf::loger::SysLog::Instance().Info("Creating map persistent states for non-instanceable maps...");
    MapPersistentStateManager::Instance().InitWorldMaps();
    m_gameTime = time(NULL);
}

void World::UnInit()
{
    MapMgr::Instance().UnInit();
}

void World::Update(unsigned int diff)
{
    m_gameTime = time(NULL);
    MapMgr::Instance().Update(diff);
}

void World::LoadConfigSettings(bool reload)
{
    if (reload)
    {
#if 0
        if (!sConfig.Reload())
        {
            sLog.outError("World settings reload fail: can't read settings from %s.", sConfig.GetFilename().c_str());
            return;
        }
#endif
    }

    ///- Read the version of the configuration file and warn the user in case of emptiness or mismatch
    unsigned int confVersion = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.ConfVersion", 0);
    if (!confVersion)
    {
        cftf::loger::SysLog::Instance().Error("*****************************************************************************");
        cftf::loger::SysLog::Instance().Error(" WARNING: mangosd.conf does not include a ConfVersion variable.");
        cftf::loger::SysLog::Instance().Error("          Your configuration file may be out of date!");
        cftf::loger::SysLog::Instance().Error("*****************************************************************************");
#if 0
        Log::WaitBeforeContinueIfNeed();
#endif
    }
    else
    {
        if (confVersion < MANGOSD_CONFIG_VERSION)
        {
            cftf::loger::SysLog::Instance().Error("*****************************************************************************");
            cftf::loger::SysLog::Instance().Error(" WARNING: Your mangosd.conf version indicates your conf file is out of date!");
            cftf::loger::SysLog::Instance().Error("          Please check for updates, as your current default values may cause");
            cftf::loger::SysLog::Instance().Error("          unexpected behavior.");
            cftf::loger::SysLog::Instance().Error("*****************************************************************************");
#if 0
            Log::WaitBeforeContinueIfNeed();
#endif
        }
    }

    ///- Read the player limit and the Message of the day from the config file
    SetPlayerLimit(mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.PlayerLimit", DEFAULT_PLAYER_LIMIT), true);

    SetMotd(mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.Motd", "Welcome to the Massive Network Game Object Server."));
    ///- Read all rates from the config file
    setConfigPos(CONFIG_FLOAT_RATE_HEALTH, "MangosdConf.Rate.Health", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_POWER_MANA, "MangosdConf.Rate.Mana", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_POWER_RAGE_INCOME, "MangosdConf.Rate.Rage.Income", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_POWER_RAGE_LOSS, "MangosdConf.Rate.Rage.Loss", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_POWER_FOCUS, "MangosdConf.Rate.Focus", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_LOYALTY, "MangosdConf.Rate.Loyalty", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_POWER_ENERGY, "MangosdConf.Rate.Energy", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_SKILL_DISCOVERY, "MangosdConf.Rate.Skill.Discovery", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_POOR, "MangosdConf.Rate.Drop.Item.Poor", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_NORMAL, "MangosdConf.Rate.Drop.Item.Normal", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_UNCOMMON, "MangosdConf.Rate.Drop.Item.Uncommon", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_RARE, "MangosdConf.Rate.Drop.Item.Rare", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_EPIC, "MangosdConf.Rate.Drop.Item.Epic", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_LEGENDARY, "MangosdConf.Rate.Drop.Item.Legendary", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_ARTIFACT, "MangosdConf.Rate.Drop.Item.Artifact", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED, "MangosdConf.Rate.Drop.Item.Referenced", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_DROP_MONEY, "MangosdConf.Rate.Drop.Money", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_XP_KILL, "MangosdConf.Rate.XP.Kill", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_XP_PETKILL, "MangosdConf.Rate.XP.PetKill", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_XP_QUEST, "MangosdConf.Rate.XP.Quest", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_XP_EXPLORE, "MangosdConf.Rate.XP.Explore", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_REPUTATION_GAIN, "MangosdConf.Rate.Reputation.Gain", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_KILL, "MangosdConf.Rate.Reputation.LowLevel.Kill", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_QUEST, "MangosdConf.Rate.Reputation.LowLevel.Quest", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_DAMAGE, "MangosdConf.Rate.Creature.Normal.Damage", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_DAMAGE, "MangosdConf.Rate.Creature.Elite.Elite.Damage", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_DAMAGE, "MangosdConf.Rate.Creature.Elite.RAREELITE.Damage", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE, "MangosdConf.Rate.Creature.Elite.WORLDBOSS.Damage", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_DAMAGE, "MangosdConf.Rate.Creature.Elite.RARE.Damage", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_HP, "MangosdConf.Rate.Creature.Normal.HP", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_HP, "MangosdConf.Rate.Creature.Elite.Elite.HP", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_HP, "MangosdConf.Rate.Creature.Elite.RAREELITE.HP", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_HP, "MangosdConf.Rate.Creature.Elite.WORLDBOSS.HP", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_HP, "MangosdConf.Rate.Creature.Elite.RARE.HP", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_SPELLDAMAGE, "MangosdConf.Rate.Creature.Normal.SpellDamage", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE, "MangosdConf.Rate.Creature.Elite.Elite.SpellDamage", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE, "MangosdConf.Rate.Creature.Elite.RAREELITE.SpellDamage", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE, "MangosdConf.Rate.Creature.Elite.WORLDBOSS.SpellDamage", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_SPELLDAMAGE, "MangosdConf.Rate.Creature.Elite.RARE.SpellDamage", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CREATURE_AGGRO, "MangosdConf.Rate.Creature.Aggro", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_REST_INGAME, "MangosdConf.Rate.Rest.InGame", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_TAVERN_OR_CITY, "MangosdConf.Rate.Rest.Offline.InTavernOrCity", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_WILDERNESS, "MangosdConf.Rate.Rest.Offline.InWilderness", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_DAMAGE_FALL, "MangosdConf.Rate.Damage.Fall", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_AUCTION_TIME, "MangosdConf.Rate.Auction.Time", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_AUCTION_DEPOSIT, "MangosdConf.Rate.Auction.Deposit", 1.0f);
    setConfig(CONFIG_FLOAT_RATE_AUCTION_CUT, "MangosdConf.Rate.Auction.Cut", 1.0f);
    setConfig(CONFIG_UINT32_AUCTION_DEPOSIT_MIN, "MangosdConf.Auction.Deposit.Min", 0);
    setConfig(CONFIG_FLOAT_RATE_HONOR, "MangosdConf.Rate.Honor", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_MINING_AMOUNT, "MangosdConf.Rate.Mining.Amount", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_MINING_NEXT, "MangosdConf.Rate.Mining.Next", 1.0f);
    setConfig(CONFIG_UINT32_RATE_MINING_LOWER, "MangosdConf.Rate.Mining.Lower", 50);
    setConfig(CONFIG_UINT32_RATE_MINING_RARE, "MangosdConf.Rate.Mining.Rare", 20);
    setConfig(CONFIG_UINT32_RATE_MINING_DARKIRON, "MangosdConf.Rate.Mining.Darkiron", 10);
    setConfig(CONFIG_UINT32_RATE_MINING_AUTOPOOLING, "MangosdConf.Rate.Mining.Autopooling", 90);
    setConfigPos(CONFIG_FLOAT_RATE_INSTANCE_RESET_TIME, "MangosdConf.Rate.InstanceResetTime", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_TALENT, "MangosdConf.Rate.Talent", 1.0f);
    setConfigPos(CONFIG_FLOAT_RATE_CORPSE_DECAY_LOOTED, "MangosdConf.Rate.Corpse.Decay.Looted", 0.5f);

    setConfigMinMax(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE, "MangosdConf.TargetPosRecalculateRange", 1.5f, CONTACT_DISTANCE, ATTACK_DISTANCE);
    setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_DAMAGE, "MangosdConf.DurabilityLossChance.Damage", 0.5f);
    setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_ABSORB, "MangosdConf.DurabilityLossChance.Absorb", 0.5f);
    setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_PARRY, "MangosdConf.DurabilityLossChance.Parry", 0.05f);
    setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_BLOCK, "MangosdConf.DurabilityLossChance.Block", 0.05f);

    setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_SAY, "MangosdConf.ListenRange.Say", 40.0f);
    setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_YELL, "MangosdConf.ListenRange.Yell", 300.0f);
    setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE, "MangosdConf.ListenRange.TextEmote", 40.0f);

    setConfigPos(CONFIG_FLOAT_GROUP_XP_DISTANCE, "MangosdConf.MaxGroupXPDistance", 74.0f);
    setConfigPos(CONFIG_FLOAT_SIGHT_GUARDER, "MangosdConf.GuarderSight", 50.0f);
    setConfigPos(CONFIG_FLOAT_SIGHT_MONSTER, "MangosdConf.MonsterSight", 50.0f);

    setConfigPos(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS, "MangosdConf.CreatureFamilyAssistanceRadius", 10.0f);
    setConfigPos(CONFIG_FLOAT_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS, "MangosdConf.CreatureFamilyFleeAssistanceRadius", 30.0f);

    ///- Read other configuration items from the config file
    setConfigMinMax(CONFIG_UINT32_COMPRESSION, "MangosdConf.Compression", 1, 1, 9);
    setConfig(CONFIG_BOOL_ADDON_CHANNEL, "MangosdConf.AddonChannel", true);
    setConfig(CONFIG_BOOL_CLEAN_CHARACTER_DB, "MangosdConf.CleanCharacterDB", true);
    setConfig(CONFIG_BOOL_GRID_UNLOAD, "MangosdConf.GridUnload", true);
    setConfig(CONFIG_UINT32_MAX_WHOLIST_RETURNS, "MangosdConf.MaxWhoListReturns", 49);
    setConfig(CONFIG_UINT32_AUTOBROADCAST_INTERVAL, "MangosdConf.AutoBroadcast", 600);

    if (getConfig(CONFIG_UINT32_AUTOBROADCAST_INTERVAL) > 0)
    {
        m_broadcastEnable = true;
    }
    else
    {
        m_broadcastEnable = false;
    }

    if (reload && m_broadcastEnable)
    {
        m_broadcastTimer->SetInterval(getConfig(CONFIG_UINT32_AUTOBROADCAST_INTERVAL) * IN_MILLISECONDS);
    }

    std::string forceLoadGridOnMaps = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.LoadAllGridsOnMaps", "");
    if (!forceLoadGridOnMaps.empty())
    {
        unsigned int pos = 0;
        unsigned int id = 0;
#if 0
        VMAP::VMapFactory::chompAndTrim(forceLoadGridOnMaps);
        while (VMAP::VMapFactory::getNextId(forceLoadGridOnMaps, pos, id))
            m_configForceLoadMapIds.insert(id);
#endif
    }
    setConfig(CONFIG_UINT32_INTERVAL_SAVE, "MangosdConf.PlayerSave.Interval", 15 * MINUTE * IN_MILLISECONDS);
    setConfigMinMax(CONFIG_UINT32_MIN_LEVEL_STAT_SAVE, "MangosdConf.PlayerSave.Stats.MinLevel", 0, 0, MAX_LEVEL);
    setConfig(CONFIG_BOOL_STATS_SAVE_ONLY_ON_LOGOUT, "MangosdConf.PlayerSave.Stats.SaveOnlyOnLogout", true);

    setConfigMin(CONFIG_UINT32_INTERVAL_GRIDCLEAN, "MangosdConf.GridCleanUpDelay", 5 * MINUTE * IN_MILLISECONDS, MIN_GRID_DELAY);
    if (reload)
    {
        MapMgr::Instance().SetGridCleanUpDelay(getConfig(CONFIG_UINT32_INTERVAL_GRIDCLEAN));
    }

    setConfig(CONFIG_UINT32_NUMTHREADS, "MangosdConf.MapUpdateThreads", 2);

    setConfigMin(CONFIG_UINT32_INTERVAL_MAPUPDATE, "MangosdConf.MapUpdateInterval", 100, MIN_MAP_UPDATE_DELAY);
    if (reload)
    {
        MapMgr::Instance().SetMapUpdateInterval(getConfig(CONFIG_UINT32_INTERVAL_MAPUPDATE));
    }

    setConfig(CONFIG_UINT32_INTERVAL_CHANGEWEATHER, "MangosdConf.ChangeWeatherInterval", 10 * MINUTE * IN_MILLISECONDS);

    if (configNoReload(reload, CONFIG_UINT32_PORT_WORLD, "MangosdConf.WorldServerPort", DEFAULT_WORLDSERVER_PORT))
    {
        setConfig(CONFIG_UINT32_PORT_WORLD, "MangosdConf.WorldServerPort", DEFAULT_WORLDSERVER_PORT);
    }

    if (configNoReload(reload, CONFIG_UINT32_GAME_TYPE, "MangosdConf.GameType", 0))
    {
        setConfig(CONFIG_UINT32_GAME_TYPE, "MangosdConf.GameType", 0);
    }

    if (configNoReload(reload, CONFIG_UINT32_REALM_ZONE, "MangosdConf.RealmZone", REALM_ZONE_DEVELOPMENT))
    {
        setConfig(CONFIG_UINT32_REALM_ZONE, "MangosdConf.RealmZone", REALM_ZONE_DEVELOPMENT);
    }

    setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ACCOUNTS, "MangosdConf.AllowTwoSide.Accounts", false);
    setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHAT, "MangosdConf.AllowTwoSide.Interaction.Chat", false);
    setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL, "MangosdConf.AllowTwoSide.Interaction.Channel", false);
    setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GROUP, "MangosdConf.AllowTwoSide.Interaction.Group", false);
    setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GUILD, "MangosdConf.AllowTwoSide.Interaction.Guild", false);
    setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_TRADE, "MangosdConf.AllowTwoSide.Interaction.Trade", false);
    setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_AUCTION, "MangosdConf.AllowTwoSide.Interaction.Auction", false);
    setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_MAIL, "MangosdConf.AllowTwoSide.Interaction.Mail", false);
    setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST, "MangosdConf.AllowTwoSide.WhoList", false);
    setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ADD_FRIEND, "MangosdConf.AllowTwoSide.AddFriend", false);

    setConfig(CONFIG_UINT32_STRICT_PLAYER_NAMES, "MangosdConf.StrictPlayerNames", 0);
    setConfig(CONFIG_UINT32_STRICT_CHARTER_NAMES, "MangosdConf.StrictCharterNames", 0);
    setConfig(CONFIG_UINT32_STRICT_PET_NAMES, "MangosdConf.StrictPetNames", 0);

    setConfigMinMax(CONFIG_UINT32_MIN_PLAYER_NAME, "MangosdConf.MinPlayerName", 2, 1, MAX_PLAYER_NAME);
    setConfigMinMax(CONFIG_UINT32_MIN_CHARTER_NAME, "MangosdConf.MinCharterName", 2, 1, MAX_CHARTER_NAME);
    setConfigMinMax(CONFIG_UINT32_MIN_PET_NAME, "MangosdConf.MinPetName", 2, 1, MAX_PET_NAME);

    setConfig(CONFIG_UINT32_CHARACTERS_CREATING_DISABLED, "MangosdConf.CharactersCreatingDisabled", 0);

    setConfigMinMax(CONFIG_UINT32_CHARACTERS_PER_REALM, "MangosdConf.CharactersPerRealm", 10, 1, 10);

    setConfig(CONFIG_BOOL_AUTOPOOLING_MINING_ENABLE, "MangosdConf.Autopooling.Mining.Enable", false);

    // must be after CONFIG_UINT32_CHARACTERS_PER_REALM
    setConfigMin(CONFIG_UINT32_CHARACTERS_PER_ACCOUNT, "MangosdConf.CharactersPerAccount", 50, getConfig(CONFIG_UINT32_CHARACTERS_PER_REALM));

    setConfigMinMax(CONFIG_UINT32_SKIP_CINEMATICS, "MangosdConf.SkipCinematics", 0, 0, 2);

    if (configNoReload(reload, CONFIG_UINT32_MAX_PLAYER_LEVEL, "MangosdConf.MaxPlayerLevel", DEFAULT_MAX_LEVEL))
    {
        setConfigMinMax(CONFIG_UINT32_MAX_PLAYER_LEVEL, "MangosdConf.MaxPlayerLevel", DEFAULT_MAX_LEVEL, 1, DEFAULT_MAX_LEVEL);
    }

    setConfigMinMax(CONFIG_UINT32_START_PLAYER_LEVEL, "MangosdConf.StartPlayerLevel", 1, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));

    setConfigMinMax(CONFIG_UINT32_START_PLAYER_MONEY, "MangosdConf.StartPlayerMoney", 0, 0, MAX_MONEY_AMOUNT);

    setConfig(CONFIG_UINT32_MAX_HONOR_POINTS, "MangosdConf.MaxHonorPoints", 75000);

    setConfigMinMax(CONFIG_UINT32_START_HONOR_POINTS, "MangosdConf.StartHonorPoints", 0, 0, getConfig(CONFIG_UINT32_MAX_HONOR_POINTS));

    setConfigMin(CONFIG_UINT32_MIN_HONOR_KILLS, "MangosdConf.MinHonorKills", HONOR_STANDING_MIN_KILL, 1);

    setConfigMinMax(CONFIG_UINT32_MAINTENANCE_DAY, "MangosdConf.MaintenanceDay", 4, 0, 6);

    setConfig(CONFIG_BOOL_ALL_TAXI_PATHS, "MangosdConf.AllFlightPaths", false);
    setConfig(CONFIG_BOOL_INSTANT_TAXI, "MangosdConf.InstantFlightPaths", false);

    setConfig(CONFIG_UINT32_MOUNT_COST, "MangosdConf.MountCost", 100000);
    setConfigMin(CONFIG_UINT32_MIN_TRAIN_MOUNT_LEVEL, "MangosdConf.MinTrainMountLevel", 40, 1);
    setConfig(CONFIG_UINT32_TRAIN_MOUNT_COST, "MangosdConf.TrainMountCost", 900000);
    setConfig(CONFIG_UINT32_EPIC_MOUNT_COST, "MangosdConf.EpicMountCost", 1000000);
    setConfigMin(CONFIG_UINT32_MIN_TRAIN_EPIC_MOUNT_LEVEL, "MangosdConf.MinTrainEpicMountLevel", 60, 1);
    setConfig(CONFIG_UINT32_TRAIN_EPIC_MOUNT_COST, "MangosdConf.TrainEpicMountCost", 9000000);

    setConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL, "MangosdConf.Instance.IgnoreLevel", false);
    setConfig(CONFIG_BOOL_INSTANCE_IGNORE_RAID, "MangosdConf.Instance.IgnoreRaid", false);

    setConfig(CONFIG_BOOL_CAST_UNSTUCK, "MangosdConf.CastUnstuck", true);
    setConfig(CONFIG_UINT32_MAX_SPELL_CASTS_IN_CHAIN, "MangosdConf.MaxSpellCastsInChain", 20);
    setConfig(CONFIG_UINT32_RABBIT_DAY, "MangosdConf.RabbitDay", 0);

    setConfig(CONFIG_UINT32_INSTANCE_RESET_TIME_HOUR, "MangosdConf.Instance.ResetTimeHour", 4);
    setConfig(CONFIG_UINT32_INSTANCE_UNLOAD_DELAY, "MangosdConf.Instance.UnloadDelay", 30 * MINUTE * IN_MILLISECONDS);

    setConfigMinMax(CONFIG_UINT32_MAX_PRIMARY_TRADE_SKILL, "MangosdConf.MaxPrimaryTradeSkill", 2, 0, 10);

    setConfigMinMax(CONFIG_UINT32_MIN_PETITION_SIGNS, "MangosdConf.MinPetitionSigns", 9, 0, 9);

    setConfig(CONFIG_UINT32_GM_LOGIN_STATE, "MangosdConf.GM.LoginState", 2);
    setConfig(CONFIG_UINT32_GM_VISIBLE_STATE, "MangosdConf.GM.Visible", 2);
    setConfig(CONFIG_UINT32_GM_ACCEPT_TICKETS, "MangosdConf.GM.AcceptTickets", 2);
    setConfig(CONFIG_UINT32_GM_TICKET_LIST_SIZE, "MangosdConf.GM.TicketListSize", 30);
    setConfig(CONFIG_BOOL_GM_TICKET_OFFLINE_CLOSING, "MangosdConf.GM.TicketOfflineClosing", false);
    setConfig(CONFIG_UINT32_GM_CHAT, "MangosdConf.GM.Chat", 2);
    setConfig(CONFIG_UINT32_GM_WISPERING_TO, "MangosdConf.GM.WhisperingTo", 2);

    setConfig(CONFIG_UINT32_GM_LEVEL_IN_GM_LIST, "MangosdConf.GM.InGMList.Level", SEC_ADMINISTRATOR);
    setConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST, "MangosdConf.GM.InWhoList.Level", SEC_ADMINISTRATOR);
    setConfig(CONFIG_BOOL_GM_LOG_TRADE, "MangosdConf.GM.LogTrade", false);

    setConfigMinMax(CONFIG_UINT32_START_GM_LEVEL, "MangosdConf.GM.StartLevel", 1, getConfig(CONFIG_UINT32_START_PLAYER_LEVEL), MAX_LEVEL);
    setConfig(CONFIG_BOOL_GM_LOWER_SECURITY, "MangosdConf.GM.LowerSecurity", false);
    setConfig(CONFIG_UINT32_GM_INVISIBLE_AURA, "MangosdConf.GM.InvisibleAura", 31748);
    setConfig(CONFIG_UINT32_GM_MAX_SPEED_FACTOR, "MangosdConf.GM.MaxSpeedFactor", 10);

    setConfig(CONFIG_UINT32_GROUP_VISIBILITY, "MangosdConf.Visibility.GroupMode", 0);

    setConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY, "MangosdConf.MailDeliveryDelay", HOUR);

    setConfigMin(CONFIG_UINT32_MASS_MAILER_SEND_PER_TICK, "MangosdConf.MassMailer.SendPerTick", 10, 1);

    setConfig(CONFIG_UINT32_UPTIME_UPDATE, "MangosdConf.UpdateUptimeInterval", 10);
    if (reload)
    {
        m_timers[WUPDATE_UPTIME]->SetInterval(getConfig(CONFIG_UINT32_UPTIME_UPDATE) * MINUTE * IN_MILLISECONDS);
        m_timers[WUPDATE_UPTIME]->Reset();
    }

    setConfig(CONFIG_UINT32_SKILL_CHANCE_ORANGE, "MangosdConf.SkillChance.Orange", 100);
    setConfig(CONFIG_UINT32_SKILL_CHANCE_YELLOW, "MangosdConf.SkillChance.Yellow", 75);
    setConfig(CONFIG_UINT32_SKILL_CHANCE_GREEN, "MangosdConf.SkillChance.Green", 25);
    setConfig(CONFIG_UINT32_SKILL_CHANCE_GREY, "MangosdConf.SkillChance.Grey", 0);

    setConfig(CONFIG_UINT32_SKILL_CHANCE_MINING_STEPS, "MangosdConf.SkillChance.MiningSteps", 75);
    setConfig(CONFIG_UINT32_SKILL_CHANCE_SKINNING_STEPS, "MangosdConf.SkillChance.SkinningSteps", 75);

    setConfig(CONFIG_UINT32_SKILL_GAIN_CRAFTING, "MangosdConf.SkillGain.Crafting", 1);
    setConfig(CONFIG_UINT32_SKILL_GAIN_DEFENSE, "MangosdConf.SkillGain.Defense", 1);
    setConfig(CONFIG_UINT32_SKILL_GAIN_GATHERING, "MangosdConf.SkillGain.Gathering", 1);
    setConfig(CONFIG_UINT32_SKILL_GAIN_WEAPON, "MangosdConf.SkillGain.Weapon", 1);

    setConfig(CONFIG_BOOL_SKILL_FAIL_LOOT_FISHING, "MangosdConf.SkillFail.Loot.Fishing", false);
    setConfig(CONFIG_BOOL_SKILL_FAIL_GAIN_FISHING, "MangosdConf.SkillFail.Gain.Fishing", false);
    setConfig(CONFIG_BOOL_SKILL_FAIL_POSSIBLE_FISHINGPOOL, "MangosdConf.SkillFail.Possible.FishingPool", true);

    setConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS, "MangosdConf.MaxOverspeedPings", 2);
    if (getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS) != 0 && getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS) < 2)
    {
        cftf::loger::SysLog::Instance().Error(std::format("MaxOverspeedPings ({}) must be in range 2..infinity (or 0 to disable check). Set to 2.", getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS)));
        setConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS, 2);
    }

    setConfig(CONFIG_BOOL_SAVE_RESPAWN_TIME_IMMEDIATELY, "MangosdConf.SaveRespawnTimeImmediately", true);
    setConfig(CONFIG_BOOL_WEATHER, "MangosdConf.ActivateWeather", true);

    setConfig(CONFIG_BOOL_ALWAYS_MAX_SKILL_FOR_LEVEL, "MangosdConf.AlwaysMaxSkillForLevel", false);

    setConfig(CONFIG_UINT32_CHATFLOOD_MESSAGE_COUNT, "MangosdConf.ChatFlood.MessageCount", 10);
    setConfig(CONFIG_UINT32_CHATFLOOD_MESSAGE_DELAY, "MangosdConf.ChatFlood.MessageDelay", 1);
    setConfig(CONFIG_UINT32_CHATFLOOD_MUTE_TIME, "MangosdConf.ChatFlood.MuteTime", 10);

    setConfig(CONFIG_BOOL_EVENT_ANNOUNCE, "MangosdConf.Event.Announce", false);

    setConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY, "MangosdConf.CreatureFamilyAssistanceDelay", 1500);
    setConfig(CONFIG_UINT32_CREATURE_FAMILY_FLEE_DELAY, "MangosdConf.CreatureFamilyFleeDelay", 7000);

    setConfig(CONFIG_UINT32_WORLD_BOSS_LEVEL_DIFF, "MangosdConf.WorldBossLevelDiff", 3);

    setConfigMinMax(CONFIG_INT32_QUEST_LOW_LEVEL_HIDE_DIFF, "MangosdConf.Quests.LowLevelHideDiff", 4, -1, MAX_LEVEL);
    setConfigMinMax(CONFIG_INT32_QUEST_HIGH_LEVEL_HIDE_DIFF, "MangosdConf.Quests.HighLevelHideDiff", 7, -1, MAX_LEVEL);

    setConfig(CONFIG_BOOL_QUEST_IGNORE_RAID, "MangosdConf.Quests.IgnoreRaid", false);

    setConfig(CONFIG_BOOL_DETECT_POS_COLLISION, "MangosdConf.DetectPosCollision", true);

    setConfig(CONFIG_BOOL_RESTRICTED_LFG_CHANNEL, "MangosdConf.Channel.RestrictedLfg", true);
    setConfig(CONFIG_BOOL_SILENTLY_GM_JOIN_TO_CHANNEL, "MangosdConf.Channel.SilentlyGMJoin", false);

    setConfig(CONFIG_BOOL_CHAT_FAKE_MESSAGE_PREVENTING, "MangosdConf.ChatFakeMessagePreventing", false);

    setConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_SEVERITY, "MangosdConf.ChatStrictLinkChecking.Severity", 0);
    setConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_KICK, "MangosdConf.ChatStrictLinkChecking.Kick", 0);

    setConfig(CONFIG_BOOL_CORPSE_EMPTY_LOOT_SHOW, "MangosdConf.Corpse.EmptyLootShow", true);
    setConfig(CONFIG_UINT32_CORPSE_DECAY_NORMAL, "MangosdConf.Corpse.Decay.NORMAL", 300);
    setConfig(CONFIG_UINT32_CORPSE_DECAY_RARE, "MangosdConf.Corpse.Decay.RARE", 900);
    setConfig(CONFIG_UINT32_CORPSE_DECAY_ELITE, "MangosdConf.Corpse.Decay.ELITE", 600);
    setConfig(CONFIG_UINT32_CORPSE_DECAY_RAREELITE, "MangosdConf.Corpse.Decay.RAREELITE", 1200);
    setConfig(CONFIG_UINT32_CORPSE_DECAY_WORLDBOSS, "MangosdConf.Corpse.Decay.WORLDBOSS", 3600);

    setConfig(CONFIG_INT32_DEATH_SICKNESS_LEVEL, "MangosdConf.Death.SicknessLevel", 11);

    setConfig(CONFIG_BOOL_DEATH_CORPSE_RECLAIM_DELAY_PVP, "MangosdConf.Death.CorpseReclaimDelay.PvP", true);
    setConfig(CONFIG_BOOL_DEATH_CORPSE_RECLAIM_DELAY_PVE, "MangosdConf.Death.CorpseReclaimDelay.PvE", true);
    setConfig(CONFIG_BOOL_DEATH_BONES_WORLD, "MangosdConf.Death.Bones.World", true);
    setConfig(CONFIG_BOOL_DEATH_BONES_BG, "MangosdConf.Death.Bones.Battleground", true);
    setConfigMinMax(CONFIG_FLOAT_GHOST_RUN_SPEED_WORLD, "MangosdConf.Death.Ghost.RunSpeed.World", 1.0f, 0.1f, 10.0f);
    setConfigMinMax(CONFIG_FLOAT_GHOST_RUN_SPEED_BG, "MangosdConf.Death.Ghost.RunSpeed.Battleground", 1.0f, 0.1f, 10.0f);

    setConfig(CONFIG_FLOAT_THREAT_RADIUS, "MangosdConf.ThreatRadius", 100.0f);
    setConfigMin(CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY, "MangosdConf.CreatureRespawnAggroDelay", 5000, 0);

    setConfig(CONFIG_BOOL_BATTLEGROUND_CAST_DESERTER, "MangosdConf.Battleground.CastDeserter", true);
    setConfigMinMax(CONFIG_UINT32_BATTLEGROUND_QUEUE_ANNOUNCER_JOIN, "MangosdConf.Battleground.QueueAnnouncer.Join", 0, 0, 2);
    setConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_START, "MangosdConf.Battleground.QueueAnnouncer.Start", false);
    setConfig(CONFIG_BOOL_BATTLEGROUND_SCORE_STATISTICS, "MangosdConf.Battleground.ScoreStatistics", false);
    setConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE, "MangosdConf.Battleground.InvitationType", 0);
    setConfig(CONFIG_UINT32_BATTLEGROUND_PREMATURE_FINISH_TIMER, "MangosdConf.BattleGround.PrematureFinishTimer", 5 * MINUTE * IN_MILLISECONDS);
    setConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH, "MangosdConf.BattleGround.PremadeGroupWaitForMatch", 0);
    setConfig(CONFIG_BOOL_OUTDOORPVP_SI_ENABLED, "MangosdConf.OutdoorPvp.SIEnabled", true);
    setConfig(CONFIG_BOOL_OUTDOORPVP_EP_ENABLED, "MangosdConf.OutdoorPvp.EPEnabled", true);

    setConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET, "MangosdConf.Network.KickOnBadPacket", false);

    setConfig(CONFIG_BOOL_PLAYER_COMMANDS, "MangosdConf.PlayerCommands", false);

    setConfig(CONFIG_UINT32_INSTANT_LOGOUT, "MangosdConf.InstantLogout", SEC_MODERATOR);

    setConfig(CONFIG_UNIT32_GUILD_PETITION_COST, "MangosdConf.Guild.PetitionCost", 1000);
    setConfigMin(CONFIG_UINT32_GUILD_EVENT_LOG_COUNT, "MangosdConf.Guild.EventLogRecordsCount", GUILD_EVENTLOG_MAX_RECORDS, GUILD_EVENTLOG_MAX_RECORDS);

    setConfig(CONFIG_UINT32_TIMERBAR_FATIGUE_GMLEVEL, "MangosdConf.TimerBar.Fatigue.GMLevel", SEC_CONSOLE);
    setConfig(CONFIG_UINT32_TIMERBAR_FATIGUE_MAX, "MangosdConf.TimerBar.Fatigue.Max", 60);
    setConfig(CONFIG_UINT32_TIMERBAR_BREATH_GMLEVEL, "MangosdConf.TimerBar.Breath.GMLevel", SEC_CONSOLE);
    setConfig(CONFIG_UINT32_TIMERBAR_BREATH_MAX, "MangosdConf.TimerBar.Breath.Max", 60);
    setConfig(CONFIG_UINT32_TIMERBAR_FIRE_GMLEVEL, "MangosdConf.TimerBar.Fire.GMLevel", SEC_CONSOLE);
    setConfig(CONFIG_UINT32_TIMERBAR_FIRE_MAX, "MangosdConf.TimerBar.Fire.Max", 1);

    setConfig(CONFIG_UINT32_LOG_WHISPERS, "MangosdConf.LogWhispers", 1);

    setConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT, "MangosdConf.PetUnsummonAtMount", false);

    setConfig(CONFIG_BOOL_ENABLE_QUEST_TRACKER, "MangosdConf.QuestTracker.Enable", 0);

#ifdef ENABLE_PLAYERBOTS
    setConfig(CONFIG_BOOL_PLAYERBOT_DISABLE, "MangosdConf.PlayerbotAI.DisableBots", true);
    setConfig(CONFIG_BOOL_PLAYERBOT_DEBUGWHISPER, "MangosdConf.PlayerbotAI.DebugWhisper", false);
    setConfigMinMax(CONFIG_UINT32_PLAYERBOT_MAXBOTS, "MangosdConf.PlayerbotAI.MaxNumBots", 3, 1, 9);
    setConfigMinMax(CONFIG_UINT32_PLAYERBOT_RESTRICTLEVEL, "MangosdConf.PlayerbotAI.RestrictBotLevel", getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL), 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
    setConfigMinMax(CONFIG_UINT32_PLAYERBOT_MINBOTLEVEL, "MangosdConf.PlayerbotAI.MinBotLevel", 1, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
    setConfig(CONFIG_FLOAT_PLAYERBOT_MINDISTANCE, "MangosdConf.PlayerbotAI.FollowDistanceMin", 0.5f);
    setConfig(CONFIG_FLOAT_PLAYERBOT_MAXDISTANCE, "MangosdConf.PlayerbotAI.FollowDistanceMax", 1.0f);

    setConfig(CONFIG_BOOL_PLAYERBOT_ALLOW_SUMMON_OPPOSITE_FACTION, "MangosdConf.PlayerbotAI.AllowSummonOppositeFaction", false);
    setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_COMBAT, "MangosdConf.PlayerbotAI.Collect.Combat", true);
    setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_QUESTS, "MangosdConf.PlayerbotAI.Collect.Quest", true);
    setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_PROFESSION, "MangosdConf.PlayerbotAI.Collect.Profession", true);
    setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_LOOT, "MangosdConf.PlayerbotAI.Collect.Loot", true);
    setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_SKIN, "MangosdConf.PlayerbotAI.Collect.Skin", true);
    setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_OBJECTS, "MangosdConf.PlayerbotAI.Collect.Objects", true);
    setConfig(CONFIG_BOOL_PLAYERBOT_SELL_TRASH, "MangosdConf.PlayerbotAI.SellGarbage", true);

    setConfig(CONFIG_BOOL_PLAYERBOT_SHAREDBOTS, "MangosdConf.PlayerbotAI.SharedBots", true);
#endif

    // WARDEN

    setConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED, "MangosdConf.Warden.WinEnabled", true);
    setConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED, "MangosdConf.Warden.OSXEnabled", false);
    setConfig(CONFIG_UINT32_WARDEN_NUM_MEM_CHECKS, "MangosdConf.Warden.NumMemChecks", 3);
    setConfig(CONFIG_UINT32_WARDEN_NUM_OTHER_CHECKS, "MangosdConf.Warden.NumOtherChecks", 7);
    setConfig(CONFIG_UINT32_WARDEN_CLIENT_BAN_DURATION, "MangosdConf.Warden.BanDuration", 86400);
    setConfig(CONFIG_UINT32_WARDEN_CLIENT_CHECK_HOLDOFF, "MangosdConf.Warden.ClientCheckHoldOff", 30);
    setConfig(CONFIG_UINT32_WARDEN_CLIENT_FAIL_ACTION, "MangosdConf.Warden.ClientCheckFailAction", 0);
    setConfig(CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY, "MangosdConf.Warden.ClientResponseDelay", 600);
    setConfig(CONFIG_UINT32_WARDEN_DB_LOGLEVEL, "MangosdConf.Warden.DBLogLevel", 0);

    m_relocation_ai_notify_delay = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.Visibility.AIRelocationNotifyDelay", 1000u);
    m_relocation_lower_limit_sq = (float)std::pow(mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.Visibility.RelocationLowerLimit", 10).Get<float>(), 2);

    m_VisibleUnitGreyDistance = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.Visibility.Distance.Grey.Unit", 1);
    if (m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
    {
        cftf::loger::SysLog::Instance().Error(std::format("MangosdConf.Visibility.Distance.Grey.Unit can't be greater {}", MAX_VISIBILITY_DISTANCE));
        m_VisibleUnitGreyDistance = MAX_VISIBILITY_DISTANCE;
    }
    m_VisibleObjectGreyDistance = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.Visibility.Distance.Grey.Object", 10);
    if (m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
    {
        cftf::loger::SysLog::Instance().Error(std::format("MangosdConf.Visibility.Distance.Grey.Object can't be greater {}", MAX_VISIBILITY_DISTANCE));
        m_VisibleObjectGreyDistance = MAX_VISIBILITY_DISTANCE;
    }

    // visibility on continents
    m_MaxVisibleDistanceOnContinents = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.Visibility.Distance.Continents", DEFAULT_VISIBILITY_DISTANCE);
    if (m_MaxVisibleDistanceOnContinents < 45 * getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO))
    {
        cftf::loger::SysLog::Instance().Error(std::format("Visibility.Distance.Continents can't be less max aggro radius {}", 45 * getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO)));
        m_MaxVisibleDistanceOnContinents = 45 * getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
    }
    else if (m_MaxVisibleDistanceOnContinents + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
    {
        cftf::loger::SysLog::Instance().Error(std::format("Visibility.Distance.Continents can't be greater {}", MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance));
        m_MaxVisibleDistanceOnContinents = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
    }

    // visibility in instances
    m_MaxVisibleDistanceInInstances = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.Visibility.Distance.Instances", DEFAULT_VISIBILITY_INSTANCE);
    if (m_MaxVisibleDistanceInInstances < 45 * getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO))
    {
        cftf::loger::SysLog::Instance().Error(std::format("Visibility.Distance.Instances can't be less max aggro radius {}", 45 * getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO)));
        m_MaxVisibleDistanceInInstances = 45 * getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
    }
    else if (m_MaxVisibleDistanceInInstances + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
    {
        cftf::loger::SysLog::Instance().Error(std::format("Visibility.Distance.Instances can't be greater {}", MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance));
        m_MaxVisibleDistanceInInstances = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
    }

    // visibility in BG/Arenas
    m_MaxVisibleDistanceInBGArenas = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.Visibility.Distance.BGArenas", DEFAULT_VISIBILITY_BGARENAS);
    if (m_MaxVisibleDistanceInBGArenas < 45 * getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO))
    {
        cftf::loger::SysLog::Instance().Error(std::format("Visibility.Distance.BGArenas can't be less max aggro radius {}", 45 * getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO)));
        m_MaxVisibleDistanceInBGArenas = 45 * getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
    }
    else if (m_MaxVisibleDistanceInBGArenas + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
    {
        cftf::loger::SysLog::Instance().Error(std::format("Visibility.Distance.BGArenas can't be greater {}", MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance));
        m_MaxVisibleDistanceInBGArenas = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
    }

    m_MaxVisibleDistanceInFlight = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.Visibility.Distance.InFlight", DEFAULT_VISIBILITY_DISTANCE);
    if (m_MaxVisibleDistanceInFlight + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
    {
        cftf::loger::SysLog::Instance().Error(std::format("Visibility.Distance.InFlight can't be greater {}", MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance));
        m_MaxVisibleDistanceInFlight = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance;
    }

    ///- Load the CharDelete related config options
    setConfigMinMax(CONFIG_UINT32_CHARDELETE_METHOD, "MangosdConf.CharDelete.Method", 0, 0, 1);
    setConfigMinMax(CONFIG_UINT32_CHARDELETE_MIN_LEVEL, "MangosdConf.CharDelete.MinLevel", 0, 0, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
    setConfig(CONFIG_UINT32_CHARDELETE_KEEP_DAYS, "MangosdConf.CharDelete.KeepDays", 30);

    if (configNoReload(reload, CONFIG_UINT32_GUID_RESERVE_SIZE_CREATURE, "MangosdConf.GuidReserveSize.Creature", 100))
    {
        setConfig(CONFIG_UINT32_GUID_RESERVE_SIZE_CREATURE, "MangosdConf.GuidReserveSize.Creature", 100);
    }
    if (configNoReload(reload, CONFIG_UINT32_GUID_RESERVE_SIZE_GAMEOBJECT, "MangosdConf.GuidReserveSize.GameObject", 100))
    {
        setConfig(CONFIG_UINT32_GUID_RESERVE_SIZE_GAMEOBJECT, "MangosdConf.GuidReserveSize.GameObject", 100);
    }

    ///- Read the "Data" directory from the config file
    std::string dataPath = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.DataDir", "./");

    // for empty string use current dir as for absent case
    if (dataPath.empty())
    {
        dataPath = "./";
    }
    // normalize dir path to path/ or path\ form
    else if (dataPath.at(dataPath.length() - 1) != '/' && dataPath.at(dataPath.length() - 1) != '\\')
    {
        dataPath.append("/");
    }

    if (reload)
    {
        if (dataPath != m_dataPath)
        {
            cftf::loger::SysLog::Instance().Error(std::format("DataDir option can't be changed at mangosd.conf reload, using current value ({}).", m_dataPath.c_str()));
        }
    }
    else
    {
        m_dataPath = dataPath;
        cftf::loger::SysLog::Instance().Info(std::format("Using DataDir {}", m_dataPath.c_str()));
    }

    setConfig(CONFIG_BOOL_VMAP_INDOOR_CHECK, "MangosdConf.vmap.enableIndoorCheck", true);
    bool enableLOS = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.vmap.enableLOS", false);
    bool enableHeight = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.vmap.enableHeight", false);
    std::string ignoreSpellIds = mt::MetaMgr::Instance().GetConf()->Get("MangosdConf.vmap.ignoreSpellIds", "");

    if (!enableHeight)
    {
        cftf::loger::SysLog::Instance().Error("VMAP height use disabled! Creatures movements and other things will be in broken state.");
    }

#if 0
    VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS);
    VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight);
    VMAP::VMapFactory::preventSpellsFromBeingTestedForLoS(ignoreSpellIds.c_str());
    sLog.outString("WORLD: VMap support included. LineOfSight:%i, getHeight:%i, indoorCheck:%i",
        enableLOS, enableHeight, getConfig(CONFIG_BOOL_VMAP_INDOOR_CHECK) ? 1 : 0);
    sLog.outString("WORLD: VMap data directory is: %svmaps", m_dataPath.c_str());

    setConfig(CONFIG_BOOL_MMAP_ENABLED, "mmap.enabled", true);
    std::string ignoreMapIds = sConfig.GetStringDefault("mmap.ignoreMapIds", "");
    MMAP::MMapFactory::preventPathfindingOnMaps(ignoreMapIds.c_str());
    sLog.outString("WORLD: MMap pathfinding %sabled", getConfig(CONFIG_BOOL_MMAP_ENABLED) ? "en" : "dis");
#endif
    setConfig(CONFIG_BOOL_ELUNA_ENABLED, "MangosdConf.Eluna.Enabled", true);

#ifdef ENABLE_ELUNA
    if (reload)
    {
        sEluna->OnConfigLoad(reload);
    }
#endif /* ENABLE_ELUNA */
#if 0
    sLog.outString();
#endif
}

void World::SetPlayerLimit(int limit, bool needUpdate)
{
    if (limit < -SEC_ADMINISTRATOR)
    {
        limit = -SEC_ADMINISTRATOR;
    }

    // lock update need
    bool db_update_need = needUpdate || (limit < 0) != (m_playerLimit < 0) || (limit < 0 && m_playerLimit < 0 && limit != m_playerLimit);

    m_playerLimit = limit;

#if 0
    if (db_update_need)
        LoginDatabase.PExecute("UPDATE `realmlist` SET `allowedSecurityLevel` = '%u' WHERE `id` = '%u'",
            uint32(GetPlayerSecurityLimit()), realmID);
#endif
}

void World::setConfig(eConfigUInt32Values index, char const* fieldname, unsigned int defvalue)
{
    if (std::string(fieldname).find("MangosdConf.") == std::string::npos) {
        CFT_ABORT();
    }
    setConfig(index, mt::MetaMgr::Instance().GetConf()->Get(fieldname, defvalue));
    if (int(getConfig(index)) < 0)
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} ({}) can't be negative. Using {} instead.", fieldname, int(getConfig(index)), defvalue));
        setConfig(index, defvalue);
    }
}

void World::setConfig(eConfigInt32Values index, char const* fieldname, int defvalue)
{
    if (std::string(fieldname).find("MangosdConf.") == std::string::npos) {
        CFT_ABORT();
    }
    setConfig(index, mt::MetaMgr::Instance().GetConf()->Get(fieldname, defvalue).Get<decltype(defvalue)>());
}

void World::setConfig(eConfigFloatValues index, char const* fieldname, float defvalue)
{
    setConfig(index, mt::MetaMgr::Instance().GetConf()->Get(std::string(fieldname), defvalue));
}

void World::setConfig(eConfigBoolValues index, char const* fieldname, bool defvalue)
{
    if (std::string(fieldname).find("MangosdConf.") == std::string::npos) {
        CFT_ABORT();
    }
    setConfig(index, mt::MetaMgr::Instance().GetConf()->Get(fieldname, defvalue).Get<decltype(defvalue)>());
}

void World::setConfigPos(eConfigFloatValues index, char const* fieldname, float defvalue)
{
    setConfig(index, fieldname, defvalue);
    if (getConfig(index) < 0.0f)
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} ({}) can't be negative. Using {} instead.", fieldname, getConfig(index), defvalue));
        setConfig(index, defvalue);
    }
}

void World::setConfigMin(eConfigUInt32Values index, char const* fieldname, unsigned int defvalue, unsigned int minvalue)
{
    setConfig(index, fieldname, defvalue);
    if (getConfig(index) < minvalue)
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} ({}) must be >= {}. Using {} instead.", fieldname, getConfig(index), minvalue, minvalue));
        setConfig(index, minvalue);
    }
}

void World::setConfigMin(eConfigInt32Values index, char const* fieldname, int defvalue, int minvalue)
{
    setConfig(index, fieldname, defvalue);
    if (getConfig(index) < minvalue)
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} ({}) must be >= {}. Using {} instead.", fieldname, getConfig(index), minvalue, minvalue));
        setConfig(index, minvalue);
    }
}

void World::setConfigMin(eConfigFloatValues index, char const* fieldname, float defvalue, float minvalue)
{
    setConfig(index, fieldname, defvalue);
    if (getConfig(index) < minvalue)
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} ({}) must be >= {}. Using {} instead.", fieldname, getConfig(index), minvalue, minvalue));
        setConfig(index, minvalue);
    }
}

void World::setConfigMinMax(eConfigUInt32Values index, char const* fieldname, unsigned int defvalue, unsigned int minvalue, unsigned int maxvalue)
{
    setConfig(index, fieldname, defvalue);
    if (getConfig(index) < minvalue)
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} ({}) must be in range {}...{}. Using {} instead.", fieldname, getConfig(index), minvalue, maxvalue, minvalue));
        setConfig(index, minvalue);
    }
    else if (getConfig(index) > maxvalue)
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} ({}) must be in range {}...{}. Using {} instead.", fieldname, getConfig(index), minvalue, maxvalue, maxvalue));
        setConfig(index, maxvalue);
    }
}

void World::setConfigMinMax(eConfigInt32Values index, char const* fieldname, int defvalue, int minvalue, int maxvalue)
{
    setConfig(index, fieldname, defvalue);
    if (getConfig(index) < minvalue)
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} ({}) must be in range {}...{}. Using {} instead.", fieldname, getConfig(index), minvalue, maxvalue, minvalue));
        setConfig(index, minvalue);
    }
    else if (getConfig(index) > maxvalue)
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} ({}) must be in range {}...{}. Using {} instead.", fieldname, getConfig(index), minvalue, maxvalue, maxvalue));
        setConfig(index, maxvalue);
    }
}

void World::setConfigMinMax(eConfigFloatValues index, char const* fieldname, float defvalue, float minvalue, float maxvalue)
{
    setConfig(index, fieldname, defvalue);
    if (getConfig(index) < minvalue)
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} ({}) must be in range {}...{}. Using {} instead.", fieldname, getConfig(index), minvalue, maxvalue, minvalue));
        setConfig(index, minvalue);
    }
    else if (getConfig(index) > maxvalue)
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} ({}) must be in range {}...{}. Using {} instead.", fieldname, getConfig(index), minvalue, maxvalue, maxvalue));
        setConfig(index, maxvalue);
    }
}

bool World::configNoReload(bool reload, eConfigUInt32Values index, char const* fieldname, unsigned int defvalue)
{
    if (!reload)
    {
        return true;
    }

    if (std::string(fieldname).find("MangosdConf.") == std::string::npos) {
        CFT_ABORT();
    }
    unsigned int val = mt::MetaMgr::Instance().GetConf()->Get(fieldname, defvalue);
    if (val != getConfig(index))
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} option can't be changed at mangosd.conf reload, using current value ({}).", fieldname, getConfig(index)));
    }

    return false;
}

bool World::configNoReload(bool reload, eConfigInt32Values index, char const* fieldname, int defvalue)
{
    if (!reload)
    {
        return true;
    }
    if (std::string(fieldname).find("MangosdConf.") == std::string::npos) {
        CFT_ABORT();
    }
    int val = mt::MetaMgr::Instance().GetConf()->Get(fieldname, defvalue);
    if (val != getConfig(index))
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} option can't be changed at mangosd.conf reload, using current value ({}).", fieldname, getConfig(index)));
    }

    return false;
}

bool World::configNoReload(bool reload, eConfigFloatValues index, char const* fieldname, float defvalue)
{
    if (!reload)
    {
        return true;
    }
    if (std::string(fieldname).find("MangosdConf.") == std::string::npos) {
        CFT_ABORT();
    }
    float val = mt::MetaMgr::Instance().GetConf()->Get(fieldname, defvalue);
    if (val != getConfig(index))
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} option can't be changed at mangosd.conf reload, using current value ({}).", fieldname, getConfig(index)));
    }

    return false;
}

bool World::configNoReload(bool reload, eConfigBoolValues index, char const* fieldname, bool defvalue)
{
    if (!reload)
    {
        return true;
    }
    if (std::string(fieldname).find("MangosdConf.") == std::string::npos) {
        CFT_ABORT();
    }
    bool val = mt::MetaMgr::Instance().GetConf()->Get(fieldname, defvalue);
    if (val != getConfig(index))
    {
        cftf::loger::SysLog::Instance().Error(std::format("{} option can't be changed at mangosd.conf reload, using current value ({}).", fieldname, getConfig(index) ? "'true'" : "'false'"));
    }

    return false;
}

unsigned int World::GetXPForLevel(unsigned int level) const
{
#if 1
    return 0;
#endif
}